﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Xml.Serialization;
using cndp.Model.IModel;

namespace cndp.Model
{
    /// <summary>
    ///     Event - Eventklassen innehåller information om en gren, t.ex. åldersklass, hopphöjd, antal rundor m.m...
    /// </summary>
    [Serializable]
    public class Event : IComparable<Event>, IEvent
    {
        #region Constructor

        public Event(int id, string gender, string bracket, double jumpHeight, int rounds, int maxDivers, int maxJudges,
            string startTime, string finishTime, bool couple)
        {
            Id = id;
            Gender = gender;
            Bracket = bracket;
            JumpHeight = jumpHeight;
            MaxDivers = maxDivers;
            MaxJudges = maxJudges;
            StartTime = startTime;
            FinishTime = finishTime;
            Rounds = rounds;
            CoupleBool = couple;
            CurrentDiver = 0;
            Jumpappendix.ReadAllJumpsFromAppendixFile("Divingregister.xlsx");
        }

        public Event()
        {
        }

        #endregion

        #region Medlemsvariabler

        [XmlElement("ID")]
        public int Id { get; set; }

        [XmlElement("COUPLE")]
        public bool CoupleBool { get; set; }

        [XmlElement("GENDER")] 
        public string Gender { get; set; }

        [XmlElement("BRACKET")]
        //OBS!!!!!!!!!!Åldersklass på svenska!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        public string Bracket { get; set; }

        [XmlElement("JUMP_HEIGHT")]
        public double JumpHeight { get; set; }

        [XmlElement("ROUNDS")]
        public int Rounds { get; set; }

        [XmlElement("MAX_DIVERS")]
        public int MaxDivers { get; set; }

        [XmlElement("MAX_JUDGES")]
        public int MaxJudges { get; set; }

        [XmlElement("START_TIME")]
        public string StartTime { get; set; } //yyyy-mm-dd tt:tt

        [XmlElement("FINISH_TIME")]
        public string FinishTime { get; set; } //yyyy-mm-dd tt:tt

        [XmlElement("CURRENT_DIVER")]
        public int CurrentDiver { get; set; }

        [XmlElement(typeof(JumpAppendix))]
        public JumpAppendix Jumpappendix = new JumpAppendix();


        #endregion

        #region Lists

        [XmlElement(typeof (DiverWithJumpCodes))] public BindingList<DiverWithJumpCodes> DiverList =
            new BindingList<DiverWithJumpCodes>();

        [XmlElement(typeof (Judge))] public BindingList<Judge> JudgeList = new BindingList<Judge>();
        [XmlElement(typeof (Eventjump))] public List<Eventjump> JumpList = new List<Eventjump>();
        [XmlElement(typeof (Diverscore))] public BindingList<Diverscore> HighScore = new BindingList<Diverscore>();

        #endregion

        #region Methods

        public void UpdateHighscore()
        {
            var d = new Diver();
            var sizeHighscore = HighScore.Count;
            var sizeJumpList = JumpList.Count;
            foreach (var key in HighScore)
            {
                key.Value = 0.0;
            }
            for (var i = 0; i < sizeHighscore; ++i)
            {
                for (var j = 0; j < sizeJumpList; ++j)
                {
                    if (JumpList[j].DiverId == HighScore[i].Key.PersonalCodeNumber)
                    {
                        HighScore[i].Value += JumpList[j].Result;
                    }
                }
            }
        }

        public void NextJumpInJumpList()
        {
            CurrentDiver++;
            if (CurrentDiver >= JumpList.Count)
            {
                CurrentDiver = JumpList.Count - 1;
            }
        }

        public void PreviousJumpInJumpList()
        {
            CurrentDiver--;
            if (CurrentDiver < 0)
            {
                CurrentDiver = 0;
            }
        }

        public void SortHighscore()
        {
            var sortedHighscore = HighScore.OrderByDescending(x => x.Value).ToList();
            HighScore = new BindingList<Diverscore>(sortedHighscore);
        }

        public string GetDivers()
        {
            var s = "";

            foreach (var c in DiverList)
            {
                s += c.Diver.Name + "    " + c.Diver.Gender + "    " + c.Diver.PersonalCodeNumber + "    " +
                     c.Diver.Nationality + "    " +
                     c.Diver.Club;
                s += "\n";
            }

            return s;
        }

        public string GetJudges()
        {
            var s = "";
            foreach (var c in JudgeList)
            {
                s += c.Name + "    " + c.Gender + "    " + c.PersonalCodeNumber + "    " + c.Nationality + "    " +
                     c.Affilliate;
                s += "\n";
            }

            return s;
        }

        #region Add/remove Diver and Judge

        public void AddDiver(string name, string gender, string personalCodeNumber, string nationality, string club)      
        {
            var diverWithJumpCodes = new DiverWithJumpCodes(name, gender, personalCodeNumber, nationality, club);
            if (((DiverList.Count < MaxDivers)) &&
                (String.Equals(diverWithJumpCodes.Diver.Gender, Gender, StringComparison.OrdinalIgnoreCase)))
            {
                DiverList.Add(diverWithJumpCodes);
                var ej = new Eventjump
                {
                    DiverId = diverWithJumpCodes.Diver.PersonalCodeNumber,
                    DiverName = diverWithJumpCodes.Diver.Name,
                    Round = 1,
                    Result = 0
                };
                JumpList.Add(ej);
                HighScore.Add(new Diverscore(diverWithJumpCodes.Diver, 0));
            }
        }

        public void RemoveDiver(string pnum)
        {
            var d = new Datacheck();
            if (d.CheckIfBirthDay(pnum))
            {
                var tempDiverWithJumpCodes = new DiverWithJumpCodes();
                tempDiverWithJumpCodes.Diver.PersonalCodeNumber = pnum;     
                DiverList.Remove(tempDiverWithJumpCodes);
                var temp = new Diverscore(new Diver(), 0);
                temp.Key.PersonalCodeNumber = pnum;
                HighScore.Remove(temp);
                for (var i = 0; i < Rounds; ++i)
                {
                    JumpList.Remove(new Eventjump {DiverId = pnum});
                }
            }
        }

        public void AddJudge(Judge d)
        {
            if (JudgeList.Count < MaxJudges)
            {
                JudgeList.Add(d);
            }
        }

        public void RemoveJudge(string pnum)
        {
            var d = new Datacheck();
            if (d.CheckIfBirthDay(pnum))
            {
                JudgeList.Remove(new Judge {PersonalCodeNumber = pnum});
            }
        }

        #endregion
        
        public void AddRoundsTojumpList()
        {
            var sizeOfOneRound = JumpList.Count;
            for (int i = 2; i <= Rounds; ++i)
            {
                for (var l = 0; l < sizeOfOneRound; ++l)
                {
                    var ej = new Eventjump(JumpList[l].JumpId, JumpList[l].JumpName, JumpList[l].DiverId,
                        JumpList[l].DiverName, JumpList[l].Difficulty,
                        JumpList[l].Style, i , JumpList[l].Result);
                    JumpList.Add(ej);
                }
            }
        }

        public void UpdateJumpcodes()
        {
            var currentJumpcode = 0;
            for (var i = 0; i < DiverList.Count; ++i)
            {
                for (var j = 0; j < JumpList.Count; ++j)
                {
                    if (DiverList[i].Diver.PersonalCodeNumber == JumpList[j].DiverId)
                    {
                        JumpList[j].JumpId = DiverList[i].JumpCodesandStyle[currentJumpcode].Jumpcode;
                        JumpList[j].Style = DiverList[i].JumpCodesandStyle[currentJumpcode].Style;
                        ++currentJumpcode;
                    }
                }
                currentJumpcode = 0;
            }
        }

        public void RandomizeJumps()
        {
            var rnd = new Random(DateTime.Now.Millisecond);
            var amountOfJumpers = JumpList.Count;
            var temp = new Eventjump();
            for (var i = 0; i < 1000; ++i)
            {
                var rand = rnd.Next(0, amountOfJumpers);
                var rand2 = rnd.Next(0, amountOfJumpers);
                temp = JumpList[rand2];
                JumpList[rand2] = JumpList[rand];
                JumpList[rand] = temp;
            }
        }

        public void SortJumplistByPoints(int round)
        {
            var startIndex = (DiverList.Count*round) - DiverList.Count;
            var endIndex = startIndex + DiverList.Count;
            
            var tempListUnsorted = new List<Eventjump>();
            for (var i = startIndex; i < endIndex; ++i)
            {
                tempListUnsorted.Add(JumpList[i]);
            }

            var tempListSorted = new List<Eventjump>();

            for (var i = HighScore.Count - 1; i >= 0; --i)
            {
                for (var j = 0; j < tempListUnsorted.Count; ++j)
                {
                    if (tempListUnsorted[j].DiverId == HighScore[i].Key.PersonalCodeNumber)
                    {
                        tempListSorted.Add(tempListUnsorted[j]);
                    }
                }
            }

            var indexOfTemplistSorted = 0;
            for (var i = startIndex; i < endIndex; ++i)
            {
                JumpList[i] = tempListSorted[indexOfTemplistSorted];
                indexOfTemplistSorted++;
            }
        }

        public void ReadFromJumpAppendix(string fileName)
        {
            Jumpappendix.ReadAllJumpsFromAppendixFile(fileName);
        }

        #region Compare/Equals

        public int CompareTo(Event other)
        {
            var tempX = new DateTime();
            var tempY = new DateTime();
            tempX = Convert.ToDateTime(StartTime);
            tempY = Convert.ToDateTime(other.StartTime);
            var result = DateTime.Compare(tempX, tempY);

            if (result < 0)
            {
                return -1;
            }
            if (result == 0)
            {
                return 0;
            }
            return 1;
        }

        public override bool Equals(object obj)
        {
            if (obj == null) return false;
            var objAsDiver = obj as Event;
            if (objAsDiver == null) return false;
            return Equals(objAsDiver);
        }

        public bool Equals(Event other)
        {
            if (other == null) return false;
            return (Id.Equals(other.Id));
        }

        #endregion

        #endregion

    }
}